// 完成日志器模块
// 1. 抽象日志器基类
// 2.派生出不同的子类（同步日志器类 & 异步日志器类）

#ifndef M_LOGGER_H
#define M_LOGGER_H
#include"util.hpp"
#include"level.hpp"
#include"format.hpp"
#include"sink.hpp"
#include<atomic>
#include<mutex>
#include<cstdarg>

namespace bitlog{
    class Logger{
        public:
            using ptr=shared_ptr<Logger>;
            Logger(const string& name,LogLevel::value level,Formatter::ptr formatter,vector<LogSink::ptr> sinks)
            :_logger_name(name),_limit_level(level),_formatter(formatter),_sinks(sinks.begin(),sinks.end())
            {}
            
            //完成构造日志消息对象过程并进行格式化，得到格式化后的日志消息字符串--然后进行落地输出
            void debug(const char* file,size_t line,const char* fmt,...){
                //通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
                //1. 判断当前的日志是否达到了输出等级
                if(_limit_level>=LogLevel::value::DEBUG) return;
                //2. 对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串
                //3. 构造LogMsg对象
                //4. 通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
                //5. 进行日志落地
                va_list al;
                va_start(al,fmt);
                log(LogLevel::value::DEBUG,file,line,fmt,al);
                va_end(al);
            }
            void info(const char* file,size_t line,const char* fmt,...){
                if(_limit_level>=LogLevel::value::INFO) return;
                va_list al;
                va_start(al,fmt);
                log(LogLevel::value::INFO,file,line,fmt,al);
                va_end(al);
            }
            void warn(const char* file,size_t line,const char* fmt,...){
                if(_limit_level>=LogLevel::value::WARNING) return;
                va_list al;
                va_start(al,fmt);
                log(LogLevel::value::WARNING,file,line,fmt,al);
                va_end(al);
            }
            void error(const char* file,size_t line,const char* fmt,...){
                if(_limit_level>=LogLevel::value::ERROR) return;
                va_list al;
                va_start(al,fmt);
                log(LogLevel::value::ERROR,file,line,fmt,al);
                va_end(al);
            }
            void fatal(const char* file,size_t line,const char* fmt,...){
                if(_limit_level>=LogLevel::value::FATAL) return;
                va_list al;
                va_start(al,fmt);
                log(LogLevel::value::FATAL,file,line,fmt,al);
                va_end(al);
            }
        protected:
            //抽象接口完成实际的落地输出--不同的日志器会有不同的实际落地方式
            void log(LogLevel::value level,const char* file,size_t line,const char* fmt,va_list al)
            {
                char* buffer;
                string msg;
                int len=vasprintf(&buffer,fmt,al);
                if(len<0){
                    msg="格式化日志消息失败\n";
                }
                else{
                    msg.assign(buffer);
                }

                LogMsg lm(_logger_name,file,line,msg,level);
                stringstream ss;
                _formatter->format(ss,lm);
                logIt(ss.str());
            }
            virtual void logIt(string&& msg)=0;
        protected:
            string _logger_name;
            atomic<LogLevel::value> _limit_level;
            Formatter::ptr _formatter;
            vector<LogSink::ptr> _sinks;
            mutex _mutex;
        //抽象建造者类
        public:
            enum class Type{
                LOGGER_SYNC=0,
                LOGGER_NSYNC
            };
            
    };
    //同步日志器
    class SyncLogger:public Logger{
        public:
            SyncLogger(const string& name,LogLevel::value level,Formatter::ptr formatter,vector<LogSink::ptr> sinks)
            :Logger(name,level,formatter,sinks)
            {
                cout<<"同步日志器："<<name<<"创建成功......\n";
            }
        private:
            void logIt(string&& msg) override
            {
                unique_lock<mutex> lock(_mutex);
                if(_sinks.empty()) {return;}
                for(auto& it:_sinks)
                {
                    it->log(msg.c_str(),msg.size());
                }
            }
    };
    //异步日志器

    //抽象建造者类
    class Bulider{
        public:
            using ptr=shared_ptr<Bulider>;
            Bulider()
            :_logger_type(Logger::Type::LOGGER_SYNC),_limit_level(LogLevel::value::DEBUG)
            {}
            void buildLoggerName(const string& name) {_logger_name=name;}
            void buildLoggerType(Logger::Type type) {_logger_type=type;}
            void buildLoggerLevel(LogLevel::value level) {_limit_level=level;}
            void buildFormatter(const string& pattern) {_formatter=make_shared<Formatter>(pattern);}
            void buildFormatter(Formatter::ptr formatter) {_formatter=formatter;}
            template<typename sinktype,typename ...Args>
            void buildSinks(Args && ...args){
                auto sink=SinkFactor::create<sinktype>(forward<Args>(args)...);
                _sinks.push_back(sink);
            }
            virtual Logger::ptr build()=0;
        protected:
            Logger::Type _logger_type;
            string _logger_name;
            atomic<LogLevel::value> _limit_level;
            Formatter::ptr _formatter;
            vector<LogSink::ptr> _sinks;
    };
    //派生出具体的建造者类---局部日志器的建造者 & 全局的日志器建造者（后边添加了全局单例管理器之后，将日志器添加全局管理）
    class LocalLoggerBuilder:public Bulider{
        public:
            Logger::ptr build() override
            {
                if(_logger_name.empty()){
                    cout<<"日志器名不能为空\n";
                    abort();
                }
                if(_formatter.get()==nullptr){
                    cout<<"日志器输出格式未指定，使用默认输出格式：";
                    cout<<"[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n\n";
                    _formatter=make_shared<Formatter>();
                }
                if(_sinks.empty()){
                    cout<<"没有指定输出方向，默认为标准输出\n";
                    _sinks.push_back(SinkFactor::create<StdoutSink>());
                }
                Logger::ptr lp;
                if(_logger_type==Logger::Type::LOGGER_NSYNC){
                    //异步日志器
                }else{
                    //同步日志器
                    lp=make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
                }
                return lp;
            }
    };
}

#endif